#include <dt-bindings/gpio/gpio.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/err.h>


#include <linux/workqueue.h>  //添加对应头文件


//用新的gpio接口
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>


// 11-新API函数-获取单个gpio描述函数
// 12-新API函数-GPIO操作函数
/**
 * rk3568-evb1-ddr4-v10.dtsi
 / {
	my_gpio:gpiol_a0 {
	    compatible = "mygpio";
	    my-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
	    pinctrl-names = "default";
	    pinctrl-0 = <&mygpio_ctrl>;
	};
  }

  &pinctrl {
  	mygpio {
    	mygpio_ctrl: my-gpio-ctrl {
        	rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
    	};
	};
  }


/**
*  学习1： 4个函数
*   gpiod_get
*   gpiod_get_optional
*   gpiod_get_index_optional
*   gpiod_get_index
*      获取设备树描述的gpio号
*/

 * 
 */


static struct gpio_desc* mygpio1;
static int num1 ; 

static struct gpio_desc* mygpio2;
static int num2 ; 
int dir; 
int value;
int irq; 



// 第一章：驱动开发
static int led_ctrl_probe(struct platform_device *pdev) //compatible的属性和dts的compatible一致，就会调用probe函数
{


	#if  1
	/**
	 *  参数1： device指针
	 *  参数2： gpio属性前缀，必须要xx-xx命令，my-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
	 *  参数3： 枚举类型， 获取到gpio以后是否进行初始化
	consumer.h 
38行	 enum gpiod_flags {
	GPIOD_ASIS	= 0,   不进行初始化
	GPIOD_IN	= GPIOD_FLAGS_BIT_DIR_SET,   初始化为输入
	GPIOD_OUT_LOW ；初始化为输出，并且输出低电平
	GPIOD_OUT_HIGH	
	GPIOD_FLAGS_BIT_DIR_VAL,
};

如果 my-gpios  描述了多个引脚
gpiod_get_index_optional 可以指定获取哪一个gpio
索引从0开始、
	 gpiod_get_index
	 带optional和不带optional 函数区别：
功能完全一致，区别在于返回值不一样，
如果获取失败，带optional返回NULL， 不带optional返回一个结构体

	 *
	 */
    mygpio1 =  gpiod_get_optional(&pdev->dev,"my",0);
	if(mygpio1 == NULL){
		printk("gpiod_get1 fail");
		return -1;
	}; 
	 num1 =  desc_to_gpio(mygpio1);
	 //打印管角gpio编号
     printk("num is1  %d  \n", num1);

    
//释放gpio,下面才能获取到，否则重复获取，报错
    gpiod_put(mygpio1);



  //参数多了一个index 下面这个函数也举一个例子
	mygpio2 =  gpiod_get_index(&pdev->dev,"my",0,0);
  //返回值判断方式不一样
    if(IS_ERR(mygpio2)){
     	printk("gpiod_get2 fail");
		return -1;
	}	 
	 num2 =  desc_to_gpio(mygpio2);
     printk("num is  %d  \n", num2);

	//workqueue_init_led();

    gpiod_direction_output(mygpio1,0);  // 设置为输出低电平 


    gpiod_set_value(mygpio1,1); // 设置为高电平

	dir = gpiod_get_direction(mygpio1);
	if(dir == GPIOF_DIR_IN){
           printk("gpio input ..  ");
	}else if(dir == GPIOF_DIR_OUT ){
		    printk("gpio output ..  ");
	}
    
	value = gpiod_get_value(mygpio1);
	printk("value is %d\n ..  ",value);

	irq = gpiod_to_irq(mygpio1);   //申请外部中断
	printk("irq is %d\n ..  ",irq);

#endif






	return 0;
}


static int led_ctrl_remove(struct platform_device *pdv)
{
	return 0;
}


static struct of_device_id led_ctrl_match_table [] = {
	{.compatible = "mygpio",}, //这里应该要跟dts的.compatible保持一致，我这里视频课程中没有写成一样，
        {},						//但他有个模糊匹配的功能，就是匹配相近的字段, 为了防止出错，大家最好写成跟dts一样的字段
	};

static struct platform_driver led_ctrl_driver = {
        .driver         = {
                .name = "mygpio",
		.owner = THIS_MODULE, 
                .of_match_table = led_ctrl_match_table,
        },
        .probe          = led_ctrl_probe,
	.remove = led_ctrl_remove,
};

static int led_ctrl_init(void)
{
	printk("%s(), __%d__\n", __func__, __LINE__);

	platform_driver_register(&led_ctrl_driver); //注册platform平台总线驱动
	return 0;
}

static void led_ctrl_exit(void)
{
	printk("%s(), __%d__\n", __func__, __LINE__);

   // gpiod_put(mygpio2);
	
	platform_driver_unregister(&led_ctrl_driver); //注销驱动
}


module_init(led_ctrl_init); //模块加载函数, linux启动， insmod 驱动的时候 
module_exit(led_ctrl_exit); //模块卸载函数

MODULE_AUTHOR("caigong, 214241976@qq.com");   // 邮箱
MODULE_DESCRIPTION("Control Led Driver");    //作者
MODULE_LICENSE("GPL");       //驱动遵守的开源协议GPL
